package memoriaintermedia;
import java.util.LinkedList;
import java.util.Queue;
public class NuevoGestorMemoria {
   /** Representa a los bloques de la memoria intermedia o buffer. */
    private boolean Modifico[];
    private Pagina[] buffer;
    private DiscoDuro disco;
    //private Pagina[] buffer;
    private boolean  estaClavado[];
    /** Numero de paginas en total en el buffer. */
    private int numeroPaginas;
    /** Posición en el buffer de la ultima pagina colocada. */
    private int posUltPaginaColocada = -1;
    /** cola para el control de sustitución basada en LRU. */
    private Queue colaLRU;
    /**
     * Crea un nuevo Gestor de memoria intermedia.
     * @param numeroPaginas cantidad de paginas en total en el buffer.
     */
    public NuevoGestorMemoria(int numeroPaginas, DiscoDuro disco) {
        this.numeroPaginas = numeroPaginas;
        colaLRU = new LinkedList<Integer>();
        this.disco =  disco;
        estaClavado = new boolean[numeroPaginas];
        buffer = new Pagina[numeroPaginas];
        Modifico = new boolean[numeroPaginas];
    }

    public Queue getColaLRU() {
        return colaLRU;
    }
    public Pagina[] getBuffer() {
        return buffer;
    }
    public void setBuffer(Pagina[] buffer) {
        this.buffer = buffer;
    }
    public int getNumeroPaginas() {
        return numeroPaginas;
    }
    public void setNumeroPaginas(int numeroPaginas) {
        this.numeroPaginas = numeroPaginas;
    }
    public int getPosUltPaginaColocada() {
        return posUltPaginaColocada;
    }
    public boolean[] getModifico() {
        return Modifico;
    }
    public DiscoDuro getDisco() {
        return disco;
    }
    public boolean[] getEstaClavado() {
        return estaClavado;
    }
    public Pagina recuperarPaginaDelBuffer(int numeroPagina) {  
        // Verificar si la pagina esta en el buffer
        int posicion = posicionDePaginaEnBuffer(numeroPagina);
        if (posicion >= 0) // la pagina esta en el buffer
        {
            // Marcar Pagina o bloque como recientemente referenciado
            colaLRU.remove(numeroPagina);
            colaLRU.add(numeroPagina);
            // devolver la pagina del buffer al solicitante
            return buffer[posicion];
        }
        return null;
    }
    /**
     * Poner una pagina en el buffer de la memoria intermedia.
     * 
     * @param pagina la pagina a ser insertado en el buffer.
     * @return la pagina que sera descartada del buffer si es necesario.
     */
    public Pagina ponerPaginaEnBuffer(Pagina pagina) {
        // Si la pagina esta en el buffer
        if (estaPaginaEnBuffer(pagina)) {//TAREA
            // no descartar ninguna pagina o bloque 
            //ver si se modificó la pagina
            //int posicion = posicionDePaginaEnBuffer(pagina.getNumeroPagina());
            colaLRU.remove(pagina.getNumeroPagina());
            colaLRU.add(pagina.getNumeroPagina());
            escribirPaginaEnDisco(pagina);
            return null;
        } // Si la pagina no esta en el buffer, pero con espacio en el buffer
        else if (!bufferLLeno()) {
            // Asignar la nueva pagina al bloque o pagina libre del buffer 
            posUltPaginaColocada++;
            buffer[posUltPaginaColocada] = pagina;
            // Actualizar la LRU
            colaLRU.remove(pagina.getNumeroPagina());
            colaLRU.add(pagina.getNumeroPagina());
            return null;
        } // Si la pagina no esta en el buffer, pero sin espacio en el buffer
        else {
            // recuperar la pagina a descartar
            int numeroPaginaDescartada = (Integer) colaLRU.remove();
            int posicion = posicionDePaginaEnBuffer(numeroPaginaDescartada);
            Pagina paginaDescartada = buffer[posicion];
            buffer[posicion] = pagina;
            //hacer que el ID de la nueva pagina sea el mas
            //recientemente utilizado
            colaLRU.add(pagina.getNumeroPagina());
            return paginaDescartada;
        }
    }
    public boolean escribirPaginaEnDisco(Pagina pagina){
           int posicion = posicionDePaginaEnBuffer(pagina.getNumeroPagina());
           if (!estaClavado[posicion] && Modifico[posicion]){//relizamos la escritura
                disco.getPaginas()[pagina.getNumeroPagina()] = recuperarPaginaDelBuffer(pagina.getNumeroPagina());
                Modifico[posicion] = false;
                return true;
            }
           else return false;
     }
    public boolean clavarPagina(Pagina p){
         int posicion = posicionDePaginaEnBuffer(p.getNumeroPagina());
         if (posicion >-1){
             estaClavado[posicion] = true;
             colaLRU.remove(p.getNumeroPagina());
             return true;
         }
         else return false;
     }
    public boolean desclavarPagina(Pagina p){
             int posicion = posicionDePaginaEnBuffer(p.getNumeroPagina());
         if (posicion >-1){
             estaClavado[posicion] = false;
            colaLRU.add(p.getNumeroPagina());
            return true;
         }
         else return false;
     }
    public int posicionDePaginaEnBuffer(int numeroPagina) {
        int posicion = -1;
        for (int i = 0; i < buffer.length; i++) {
            if ((buffer[i] != null)
                    && (numeroPagina == buffer[i].getNumeroPagina())) {
                posicion = i;
                break;
            }
        }
        return posicion;
    }
    public boolean estaPaginaEnBuffer(Pagina pagina) {
        return (posicionDePaginaEnBuffer(pagina.getNumeroPagina()) != -1);
    }
    private boolean bufferLLeno() {

        return numeroPaginas-1  == posUltPaginaColocada;
    }//para revisar
    @Override
    public String toString() {
        String resultado = "";
        for (int i = 0; i < buffer.length; i++) {
            resultado += "Pagina[" + i + "]: " + buffer[i] + "\n";
        }
        return resultado + "\n" + this.colaLRU;
    }
    public void ModificarPagina(int numPagina, String newDato){
        int pos = posicionDePaginaEnBuffer(numPagina);
        if(!Modifico[pos]){
            Pagina p = recuperarPaginaDelBuffer(numPagina);
            p.setDatos(newDato);        
            Modifico[pos] = true;
            buffer[pos] = p;
            colaLRU.remove(p.getNumeroPagina());
            colaLRU.add(p.getNumeroPagina());
        }
    }
}